package sk.stuba.fiit.pki.core;

import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.SignatureException;
import java.security.cert.CRLException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.List;

import org.bouncycastle.asn1.x509.CRLNumber;
import org.bouncycastle.asn1.x509.CRLReason;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.x509.X509V2CRLGenerator;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;

import sun.security.x509.X509CRLImpl;

public class CrlManager {

	private final static int ONE_DAY = 1000 * 60 * 60 * 24;
	private X509V2CRLGenerator crlGen;
	private static CrlManager singelton;
	
	public static CrlManager getInstance(){
		if(singelton==null)
			return new CrlManager();
		return singelton;
	}

	private CrlManager() {
		crlGen = new X509V2CRLGenerator();
		singelton = this;
	}

	public X509CRL generateCRL( BigInteger crlSerialNum,List<BigInteger> certSerialNum,X509Certificate caCrlCert, PrivateKey privateKey) throws CertificateParsingException,
	InvalidKeyException, CRLException, NoSuchProviderException,	SecurityException, SignatureException, IOException {
		return procesingCRLGenerator(null, certSerialNum,crlSerialNum,caCrlCert,privateKey);
	}

	public X509CRL updateCRL(X509CRL crl, BigInteger crlSerialNum,List<BigInteger> certSerialNum,X509Certificate caCrlCert, PrivateKey privateKey) throws CertificateParsingException,
	InvalidKeyException, CRLException, NoSuchProviderException, SecurityException, SignatureException, IOException {
		return procesingCRLGenerator(crl,  certSerialNum, crlSerialNum,caCrlCert,privateKey);
	}
	
	@SuppressWarnings("deprecation")
	private X509CRL procesingCRLGenerator(X509CRL existingCRL,
			List<BigInteger> certSerilNumber, BigInteger crlSerialNumber, X509Certificate caCrlCert, PrivateKey privateKey) throws CertificateParsingException,
			CRLException, InvalidKeyException, NoSuchProviderException,
			SecurityException, SignatureException, IOException {
		if(crlSerialNumber==null)
			throw new CRLException("Serial number can not by empty");
		
		Date now = new Date();
		Date nextUpdate = new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24);

		crlGen.setIssuerDN(caCrlCert.getIssuerX500Principal());
		crlGen.setThisUpdate(now);
		crlGen.setNextUpdate(nextUpdate);
		crlGen.setSignatureAlgorithm("SHA1withRSA");

		if (existingCRL != null) {
			crlGen.addCRL(existingCRL);
		}
		
		for (BigInteger serialNumber : certSerilNumber) {
			crlGen.addCRLEntry(serialNumber, now, CRLReason.unspecified);			
		}

		crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(caCrlCert));
		crlGen.addExtension(X509Extensions.CRLNumber, false, new CRLNumber(crlSerialNumber));

		X509CRL crl = crlGen.generateX509CRL(privateKey, "BC");
		X509CRL crlfromByte = new X509CRLImpl(crl.getEncoded());
		return crl;
	}

}
